package com.jthinker.dao.impl;

import com.jthinker.dao.BaseDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by chen.gang on 2015/2/10.
 */
@Repository
public class BaseDaoImpl implements BaseDao
{
    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDao.class);

    @Resource
    private JdbcTemplate jdbcTemplate;

    private final RecordRowMapper RECORD_ROW_MAPPER = new RecordRowMapper();

    @Override
    public Map<String, Object> read(String sql, Object... params)
    {
        List<Map<String, Object>> list = query(sql, params);
        LOGGER.debug("SQL >>> {}", sql);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }

    @Override
    public <T> T read(String sql, Class<T> clazz, Object... params)
    {
        List<T> list = query(sql, clazz, params);
        LOGGER.debug("SQL >>> {}", sql);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }

    @Override
    public List<Map<String, Object>> query(String sql, Object... params)
    {
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.query(sql, params, RECORD_ROW_MAPPER);
    }

    @Override
    public <T> List<T> query(String sql, Class<T> clazz, Object... params)
    {
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper(clazz), params);
    }

    @Override
    public List<Map<String, Object>> queryPagination(String sql, int page, int pageSize, Object... params)
    {
        int start = (page - 1 > 0 ? page - 1 : 0) * pageSize;
        return queryPagination2(sql, start, pageSize, params);
    }

    @Override
    public List<Map<String, Object>> queryPagination2(String sql, int start, int length, Object... params)
    {
        StringBuilder sb = new StringBuilder(sql);
        sb.append(" LIMIT ").append(start).append(",").append(length);

        LOGGER.debug("SQL >>> {}", sb);
        return jdbcTemplate.query(sb.toString(), params, RECORD_ROW_MAPPER);
    }

    @Override
    public Integer queryTotal(String sql, Object... params)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT COUNT(1) FROM (").append(sql).append(") AS RES LIMIT 1");
        LOGGER.debug("SQL >>> {}", sb);
        return jdbcTemplate.queryForObject(sb.toString(), params, Integer.class);
    }

    @Override
    public Integer queryTotal(String table, String where, Object... params)
    {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT COUNT(1) FROM ").append(table).append(" WHERE 1=1 ");
        if (StringUtils.isNotBlank(where))
        {
            sql.append("AND ");
            sql.append(where);
        }
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.queryForObject(sql.toString(), params, Integer.class);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> clazz, Object... params)
    {
        return jdbcTemplate.queryForObject(sql, clazz, params);
    }

    @Override
    public int insert(String table, Map<String, Object> record)
    {
        StringBuilder sql = new StringBuilder("INSERT INTO ");
        StringBuilder sufix = new StringBuilder();

        sql.append(table).append(" (");
        sufix.append("  VALUES(");

        for (Map.Entry<String, Object> entry : record.entrySet())
        {
            sql.append(entry.getKey()).append(",");
            sufix.append(" ?,");
        }
        sql.deleteCharAt(sql.length() - 1).append(")");
        sufix.deleteCharAt(sufix.length() - 1).append(")");

        sql.append(sufix);
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.update(sql.toString(), record.values().toArray());
    }

    @Override
    public int update(String sql, Object... params)
    {
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.update(sql, params);
    }

    @Override
    public int update(String table, Map<String, Object> record, String where, Object... params)
    {
        List<Object> list = new ArrayList<Object>();
        StringBuilder sql = new StringBuilder("UPDATE ");
        sql.append(table).append(" SET ");

        for (Map.Entry<String, Object> entry : record.entrySet())
        {
            sql.append(entry.getKey()).append("=?,");
            list.add(entry.getValue());
        }
        sql.deleteCharAt(sql.length() - 1).append(" WHERE ").append(where);

        int listSize = list.size();
        Object[] total = new Object[listSize + params.length];

        System.arraycopy(list.toArray(), 0, total, 0, listSize);
        System.arraycopy(params, 0, total, listSize, params.length);
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.update(sql.toString(), total);
    }

    @Override
    public int delete(String table, String where, Object... params)
    {
        StringBuilder sql = new StringBuilder("DELETE FROM ");
        sql.append(table).append(" WHERE ").append(where);
        LOGGER.debug("SQL >>> {}", sql);
        return jdbcTemplate.update(sql.toString(), params);
    }


   /* class BaseRowMapper implements RowMapper<Map<String, Object>>
    {
        @Override
        public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException
        {
            ResultSetMetaData metaData = rs.getMetaData();
            int colCount = metaData.getColumnCount();

            Map<String, Object> row = new HashMap<String, Object>();

            for (int i = 1; i <= colCount; ++i)
            {
                String colName = metaData.getColumnLabel(i).toLowerCase();
                Object val = rs.getObject(i);
                row.put(colName, val);
            }
            return row;
        }
    }*/

    class RecordRowMapper implements RowMapper<Map<String, Object>>
    {
        @Override
        public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException
        {
            ResultSetMetaData metaData = rs.getMetaData();
            int colCount = metaData.getColumnCount();

            Map<String, Object> row = new HashMap<String, Object>();

            for (int i = 1; i <= colCount; ++i)
            {
                String colName = metaData.getColumnLabel(i).toLowerCase();
                Object val = rs.getObject(i);
                row.put(colName, val);
            }
            return row;
        }
    }

}
